﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Net;
using System.IO;
using Core.WebScaner;

namespace WebScanner
{
    class SiteMapWebRequest
    {

        private void SendWebRequest(WebRequestProperties webRequestProperties)
        {
            if (webRequestProperties.Uri.AbsolutePath.Contains(".") && !webRequestProperties.Uri.AbsolutePath.Contains(".php") && !webRequestProperties.Uri.AbsolutePath.Contains(".html") && !webRequestProperties.Uri.AbsolutePath.Contains(".aspx"))
            {
                webRequestProperties.FileType = FileType.File;
            }            
            else
            {
                webRequestProperties.FileType = FileType.Page;
            }

            try
            {
                System.Net.WebRequest reqGET = System.Net.WebRequest.Create(webRequestProperties.Uri);
                using (System.Net.WebResponse response = reqGET.GetResponse())
                {
                    System.IO.Stream stream = response.GetResponseStream();
                    System.IO.StreamReader sr = new System.IO.StreamReader(stream, Encoding.UTF8);
                    HttpWebResponse httpResponse = (HttpWebResponse)response;
                    webRequestProperties.StatusCode = httpResponse.StatusCode;
                                        
                    if (webRequestProperties.FileType == FileType.Page)
                    {
                        //Нужно избавляться от webRequestProperties.Content, а то out of memory
                        webRequestProperties.Content = sr.ReadToEnd();

                        if (!webRequestProperties.Content.Contains("<html"))
                        {
                            webRequestProperties.FileType = FileType.AnotherType;
                        }
                        else
                        {
                            webRequestProperties.LinksOnPage = new HtmlPageParser().GetAllUrls(webRequestProperties.Content).ToList();
                            Regex rgxTitle = new Regex(@"<title>(?<title>.+)</title>");
                            Match match = rgxTitle.Match(webRequestProperties.Content);
                            webRequestProperties.Title = match.Groups["title"].Value;
                        }
                    }
                }
            }
            catch (WebException e)
            {
                using (WebResponse response = e.Response)
                {
                    if (response != null)
                    {
                        HttpWebResponse httpResponse = (HttpWebResponse)response;
                        webRequestProperties.StatusCode = httpResponse.StatusCode;
                    }
                    else
                    {
                        webRequestProperties.StatusCode = HttpStatusCode.RequestTimeout;
                    }                   
                }
            }


        }
                
        public void GetContent(List<WebRequestProperties> uriList)
        {
            var webRequestPropertiesList = uriList.Where(x => x.StatusCode != HttpStatusCode.OK).ToList();

            this.MultiThreaded(webRequestPropertiesList);

            Console.WriteLine("Обработано {0} реквестов", webRequestPropertiesList.Count());
        }

        private void MultiThreaded(List<WebRequestProperties> listProperties)
        {

            List<ManualResetEvent> doneEvents = new List<ManualResetEvent>();
            foreach (var properties in listProperties)
            {
                ManualResetEvent resetEvent = new ManualResetEvent(false);
                doneEvents.Add(resetEvent);
                ThreadWrapper tw = new ThreadWrapper(resetEvent, properties);
                WaitCallback callBack = new WaitCallback(tw.ThreadPoolCallback);
                ThreadPool.QueueUserWorkItem(callBack);

                if (doneEvents.Count == 64)
                {
                    WaitHandle.WaitAll(doneEvents.ToArray());
                    doneEvents.Clear();
                }
            }

            if (doneEvents.Count > 0)
            {
                WaitHandle.WaitAll(doneEvents.ToArray());
            }

        }

        private class ThreadWrapper : IDisposable
        {

            private ManualResetEvent doneEvent;
            WebRequestProperties _property;

            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
            protected virtual void Dispose(bool disposing)
            {
                if (disposing)
                    if (doneEvent != null)
                    {
                        doneEvent.Dispose();
                        doneEvent = null;
                    }
            }
            ~ThreadWrapper()
            {
                Dispose(false);
            }
            public ThreadWrapper(ManualResetEvent doneEvent, WebRequestProperties property)
            {
                this.doneEvent = doneEvent;
                _property = property;
            }

            public void ThreadPoolCallback(Object threadContext)
            {
                new SiteMapWebRequest().SendWebRequest(_property);
                this.doneEvent.Set();
            }
        }

    }

}
